package com.cug.smartranch.animal.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cug.smartranch.animal.admin.common.enums.DeleteEnum;
import com.cug.smartranch.animal.admin.common.enums.FeedEquipmentStatusEnum;
import com.cug.smartranch.animal.admin.common.enums.FeedPlanStatusEnum;
import com.cug.smartranch.animal.admin.dao.entity.FeedDetail;
import com.cug.smartranch.animal.admin.dao.entity.FeedEquipment;
import com.cug.smartranch.animal.admin.dao.entity.FeedPlan;
import com.cug.smartranch.animal.admin.dao.mapper.FeedDetailMapper;
import com.cug.smartranch.animal.admin.dao.mapper.FeedEquipmentMapper;
import com.cug.smartranch.animal.admin.dao.mapper.FeedPlanMapper;
import com.cug.smartranch.animal.admin.dto.req.FeedPlanPageQueryReqDTO;
import com.cug.smartranch.animal.admin.dto.req.PlanSaveReqDTO;
import com.cug.smartranch.animal.admin.dto.req.PlanUpdateReqDTO;
import com.cug.smartranch.animal.admin.dto.resp.FeedPlanPageQueryRespDTO;
import com.cug.smartranch.animal.admin.service.FeedPlanService;
import com.cug.smartranch.framework.exception.ClientException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 喂养计划记录业务逻辑实现层
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class FeedPlanServiceImpl extends ServiceImpl<FeedPlanMapper, FeedPlan> implements FeedPlanService {

    private final FeedPlanMapper feedPlanMapper;
    private final FeedEquipmentMapper feedEquipmentMapper;
    private final FeedDetailMapper feedDetailMapper;

    /**
     * 创建喂养计划记录
     *
     * @param requestParam
     */
    @Override
    public void createPlan(PlanSaveReqDTO requestParam) {
        // 参数判空校验
        if (Objects.isNull(requestParam)) {
            throw new ClientException("参数不能为空！");
        }
        if (Objects.isNull(requestParam.getPlanFeedAmount())) {
            throw new ClientException("计划投放量不能为空！");
        }
        if (Objects.isNull(requestParam.getFeedTime())) {
            throw new ClientException("计划喂养时间不能为空！");
        }
        if (StrUtil.isBlank(requestParam.getName())) {
            throw new ClientException("计划名称不能为空！");
        }
        if (Objects.isNull(requestParam.getFeedCategory())) {
            throw new ClientException("饲料种类不能为空！");
        }
        if (Objects.isNull(requestParam.getAnimalGroup())) {
            throw new ClientException("喂养动物群体不能为空！");
        }
        // 重名校验
        LambdaQueryWrapper<FeedPlan> queryWrapper = Wrappers.lambdaQuery(FeedPlan.class);
        queryWrapper.eq(FeedPlan::getName, requestParam.getName());
        FeedPlan isExist = feedPlanMapper.selectOne(queryWrapper);
        if (Objects.nonNull(isExist)) {
            throw new ClientException("同名计划已存在，请更改计划名称！");
        }
        // 创建计划
        FeedPlan feedPlan = FeedPlan.builder()
                .name(requestParam.getName())
                .feedTime(new Date(requestParam.getFeedTime()))
                .animalGroup(requestParam.getAnimalGroup())
                .feedCategory(requestParam.getFeedCategory())
                .planFeedAmount(requestParam.getPlanFeedAmount())
                .actualFeedAmount(0)
                .status(FeedPlanStatusEnum.NOT_STARTED.getType())
                .build();
        feedPlanMapper.insert(feedPlan);
    }

    @Override
    public void executeUncompletedPlan() {

        // 查询数据库所有启动的喂养设备
        LambdaQueryWrapper<FeedEquipment> equipmentQueryWrapper = Wrappers.lambdaQuery(FeedEquipment.class);
        equipmentQueryWrapper.eq(FeedEquipment::getStatus, FeedEquipmentStatusEnum.STARTED.getType());
        List<FeedEquipment> feedEquipmentList = feedEquipmentMapper.selectList(equipmentQueryWrapper);
        //FeedCategoryEnum的key为饲料种类
        Map<Integer, List<FeedEquipment>> feedEquipmentMap = feedEquipmentList.stream()
                .collect(Collectors.groupingBy(FeedEquipment::getFeedCategory));

        // 查询数据库中所有未完成的计划
        LambdaQueryWrapper<FeedPlan> queryWrapper = Wrappers.lambdaQuery(FeedPlan.class);
        queryWrapper.lt(FeedPlan::getFeedTime, new Date());
        queryWrapper.apply("plan_feed_amount > actual_feed_amount");
        queryWrapper.in(FeedPlan::getStatus, Arrays.asList(FeedPlanStatusEnum.NOT_STARTED.getType(), FeedPlanStatusEnum.IN_PROGRESS.getType()));
        queryWrapper.eq(FeedPlan::getDelFlag, DeleteEnum.NORMAL.getType());
        List<FeedPlan> uncompletedPlanList = feedPlanMapper.selectList(queryWrapper);

        // 依次执行每一个计划
        List<FeedDetail> feedDetailList = new ArrayList<>();
        for (FeedPlan plan : uncompletedPlanList) {
            Integer planFeedAmount = plan.getPlanFeedAmount();
            Integer actualFeedAmount = plan.getActualFeedAmount();
            Integer needFeedAmount = planFeedAmount - actualFeedAmount;
            List<FeedEquipment> equipments = feedEquipmentMap.get(plan.getFeedCategory());
            for (FeedEquipment equipment : equipments) {
                Integer remainFeedAmount = equipment.getRemainFeedAmount();
                if (remainFeedAmount <= 0) {
                    continue;
                } else if (0 < remainFeedAmount && remainFeedAmount < needFeedAmount) {
                    // 更新该设备库存为0的逻辑
                    equipment.setRemainFeedAmount(0);
                    needFeedAmount -= remainFeedAmount;
                    // 添加喂养详情记录到list
                    FeedDetail feedDetail = FeedDetail.builder()
                            .equipmentName(equipment.getName())
                            .animalGroup(plan.getAnimalGroup())
                            .feedCategory(plan.getFeedCategory())
                            .feedAmount(remainFeedAmount)
                            .feedTime(new Date())
                            .build();
                    feedDetailList.add(feedDetail);
                } else if (remainFeedAmount >= needFeedAmount) {
                    // 更新该设备库存为remainFeedAmount-needFeedAmount
                    equipment.setRemainFeedAmount(remainFeedAmount - needFeedAmount);
                    // 添加喂养详情记录到list
                    FeedDetail feedDetail = FeedDetail.builder()
                            .equipmentName(equipment.getName())
                            .animalGroup(plan.getAnimalGroup())
                            .feedCategory(plan.getFeedCategory())
                            .feedAmount(needFeedAmount)
                            .feedTime(new Date())
                            .build();
                    feedDetailList.add(feedDetail);
                    needFeedAmount = 0;
                    break;
                }
            }
            // 根据needFeedAmount来更新plan记录
            if (needFeedAmount == 0) {
                plan.setStatus(FeedPlanStatusEnum.COMPLETED.getType());
            } else {
                plan.setStatus(FeedPlanStatusEnum.IN_PROGRESS.getType());
            }
            plan.setActualFeedAmount(planFeedAmount - needFeedAmount);
        }
        // 更新数据库，并插入喂养详情记录
        feedPlanMapper.updateById(uncompletedPlanList);
        feedEquipmentMapper.updateById(feedEquipmentList);
        feedDetailMapper.insert(feedDetailList);
    }

    @Override
    public IPage<FeedPlanPageQueryRespDTO> selectAllFeedPlan(FeedPlanPageQueryReqDTO requestParam) {
        // 构建分页查询参数
        Page<FeedPlan> page = new Page<>(requestParam.getPageNo(), requestParam.getPageSize());
        // 构建查询条件
        LambdaQueryWrapper<FeedPlan> queryWrapper = Wrappers.lambdaQuery(FeedPlan.class);
        queryWrapper.eq(FeedPlan::getDelFlag, DeleteEnum.NORMAL.getType());
        // 查询分页数据
        Page<FeedPlan> tempResult = feedPlanMapper.selectPage(page, queryWrapper);
        // 转换
        IPage<FeedPlanPageQueryRespDTO> result = tempResult.convert(e -> {
            FeedPlanPageQueryRespDTO respDTO = BeanUtil.toBean(e, FeedPlanPageQueryRespDTO.class);
            return respDTO;
        });
        return result;
    }

    @Override
    public void deletePlan(Long id) {
        FeedPlan feedPlan = feedPlanMapper.selectById(id);
        feedPlan.setDelFlag(DeleteEnum.DELETE.getType());
        feedPlanMapper.updateById(feedPlan);
    }

    /**
     * 修改计划投放量
     * @param requestParam
     */
    @Override
    public void updatePlan(PlanUpdateReqDTO requestParam) {
        // 参数判空校验
        if (Objects.isNull(requestParam)) {
            throw new ClientException("参数不能为空！");
        }
        if (Objects.isNull(requestParam.getId())) {
            throw new ClientException("计划id不能为空");
        }
        if (Objects.isNull(requestParam.getPlanFeedAmount())) {
            throw new ClientException("修改的投放量不能为空！");
        }
        FeedPlan feedPlan = feedPlanMapper.selectById(requestParam.getId());
        Integer actualFeedAmount = feedPlan.getActualFeedAmount();
        if (requestParam.getPlanFeedAmount() < actualFeedAmount) {
            throw new ClientException("修改的投放量小于已投放量！请重新输入！");
        }
        feedPlan.setPlanFeedAmount(requestParam.getPlanFeedAmount());
        if(requestParam.getPlanFeedAmount() > actualFeedAmount){
            feedPlan.setStatus(FeedPlanStatusEnum.IN_PROGRESS.getType());
        }else if(requestParam.getPlanFeedAmount().equals(actualFeedAmount)){
            feedPlan.setStatus(FeedPlanStatusEnum.COMPLETED.getType());
        }
        feedPlanMapper.updateById(feedPlan);
    }
}
